package com.example.common.filter;

import com.example.common.repository.TokenRepository;
import com.example.common.session.UserSession;
import com.example.common.util.JwtUtil;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.NonNull;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Collections;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final TokenRepository tokenRepository;

    public JwtAuthenticationFilter(TokenRepository tokenRepository) {
        this.tokenRepository = tokenRepository;
    }

    @Override
    protected void doFilterInternal(
            @NonNull HttpServletRequest request,
            @NonNull HttpServletResponse response,
            @NonNull FilterChain filterChain) throws ServletException, IOException {

        logger.info("Processing jwt authentication request");

        if (request.getServletPath().contains("/auth/register")
                || request.getServletPath().contains("/auth/login")
                || request.getServletPath().contains("/auth/logout")
                || request.getServletPath().contains("/auth/refresh")
                || request.getServletPath().contains("/auth/loginByUserId")) {
            logger.info("Skipping authentication for registration/login");
            filterChain.doFilter(request, response);
            return;
        }

        String token = request.getHeader("Authorization");
        if (!StringUtils.hasLength(token) || !token.startsWith("Bearer ")) {
            logger.error("Invalid or expired token");
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return;
        }

        token = token.substring(7);
        logger.info("Token: " + token);

        if (!tokenRepository.hasToken(token)) {
            logger.error("The token is expired or invalid");
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return;
        }

        Claims claims;

        try {
            claims = JwtUtil.parseToken(token);
        } catch (Exception e) {
            logger.error("Invalid or expired token");
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return;
        }

        if (claims.get("state") == "2") {
            logger.error("User account is disabled");
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return;
        }

        UserSession userDetails = new UserSession(claims, Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                userDetails,
                null,
                userDetails.getAuthorities());
        authToken.setDetails(
                new WebAuthenticationDetailsSource().buildDetails(request)
        );

        SecurityContextHolder.getContext().setAuthentication(authToken);

        logger.info("User authenticated successfully");

        filterChain.doFilter(request, response);
    }
}
